/**
 * 
 */
package recognition.preprocessor;

import handwritten.gesture.Gesture;
import handwritten.gesture.MultiGesture;

import java.util.ArrayList;

import org.apache.commons.math3.analysis.interpolation.NevilleInterpolator;
import org.apache.commons.math3.analysis.polynomials.PolynomialFunctionLagrangeForm;

import utility.math.Vector2D;

/**
 * @author tioz
 * 
 * Take the stroke two by two and resample them with the same number of point
 * 
 */

public class Resampling extends Preprocessor {


	
	double density = 1;
	
	/**
	 * 
	 */
	public Resampling(double density) {
		this.density = density;
		
	}

	/* (non-Javadoc)
	 * @see textRecognition.preprocessor.Preprocessor#preprocess(textRecognition.gesture.MultiGesture)
	 */
	@SuppressWarnings("unchecked")
	@Override
	
	//TODO unfinished
	public boolean preprocess(MultiGesture gest) {
		
	
		ArrayList<Vector2D> oldP,newP;
		double interval,length=0;
		double nPoint=0;
		//Vector2D p;
		boolean isFirst= true;
		double[] xs = null,ys=null;
		double point=0;
		
		double tmp1;
		double tmp2;
		
		int start=0;
		//number of point used for resampling
		int size = 2;
		double slope;
		int index;
		
		//data for the neuvil interpolator
		xs = new double[size];
	    ys = new double[size];
		
		NevilleInterpolator interpolator		= new NevilleInterpolator();
		PolynomialFunctionLagrangeForm function = null; 	
		
		//System.out.println("Resampling Gesture ");
		for(Gesture g : gest.getCollection())
		{
			System.out.println("gesture");
			
			//clone the container not the contant
			oldP= (ArrayList<Vector2D>) g.getPath().clone(); 
			//newP is a reference on the new path
			newP= g.getPath();    								
			newP.clear();
			//isFirst= true;
		
			start =0;
			//put the first point of the gesture into newP
			newP.add(oldP.get(start));
			
		
			for(int i=1; i<oldP.size() ; i++)
			{

				length=oldP.get(i).minus(oldP.get(start)).norm();

				
				if((nPoint = density*length) >=1)
				{
					 					
				    //for non linear interp
					//int size= i-start+1;
					index = 0;
					
					slope = slop(oldP.get(start),oldP.get(i));
					if(Double.compare(Math.abs(slope),1)< 0)
					 {
					 	
						
						for(int j=start; j <= i ;j +=i-start )
						{
							xs[index] = oldP.get(j).getX();
							ys[index] = oldP.get(j).getY();
							index++;
						}
						

						//System.out.println("before");
						function =  interpolator.interpolate(xs,ys);
						//hypothenus interval
						interval = (oldP.get(i).getX()-oldP.get(start).getX())/(nPoint); 
						//x interval
						interval = interval * Math.cos(Math.atan(slope));
						
						 for(int p1=0;p1<nPoint;p1++)
						 {
							 
							  point = oldP.get(start).getX()+p1*interval;
							  //System.out.println("point "+ p1);
							  //System.out.println(point);
							  newP.add(new Vector2D(point,function.value(point)));
						 }
					 }
					 else
					 {
						 //we inverse the axis		
						 
						 slope = inversSlop(oldP.get(start),oldP.get(i));
						    
							for(int j=start; j <= i ;j+=i-start )
							{
								//System.out.println(oldP.size());
								//x take a minus because of the axis rotation
								xs[index] = -oldP.get(j).getX();
								ys[index] = oldP.get(j).getY();
								index++;
							}
						    
					 
														
						 //System.out.println("Slope " + slop(oldP.get(start),oldP.get(i)) );
						//System.out.println("y before"); 
						function =  interpolator.interpolate(ys,xs);
						//System.out.println("y after");
						interval = (oldP.get(i).getY()-oldP.get(start).getY())/(nPoint); 
						interval = interval * Math.cos(Math.atan(slope)); 
						
						 for(int p1=0;p1<nPoint;p1++)
						 {
							// System.out.println("looop");
							 point = oldP.get(start).getY()+p1*interval;
							 //System.out.println("point "+ p1);
							 //System.out.println(point);
							 newP.add(new Vector2D(-function.value(point),point));
						 }
					 }
					 
					 length =0;
					 start  =i;
					 oldP.set(i,newP.get(newP.size()-1));
					// System.out.println(newP.get(newP.size()-1).display());
				}
				
			}
			
		}
		
		return true;
	}


	
	private double slop(Vector2D v2,Vector2D v1){
		return (v1.getY() - v2.getY())/(v1.getX() - v2.getX());
	}

	private double inversSlop(Vector2D v2,Vector2D v1){
		return (v1.getX() - v2.getX())/(v1.getY() - v2.getY());
	}
}
